package org.xnat.xnatfs.filter;

import java.io.IOException;
import java.util.ArrayList;

import javax.security.auth.login.LoginException;

import com.bradmcevoy.http.Auth;
import com.bradmcevoy.http.Filter;
import com.bradmcevoy.http.FilterChain;
import com.bradmcevoy.http.Request;
import com.bradmcevoy.http.Response;
import com.bradmcevoy.http.ServletRequest;

/**
 * Milton filter that authenticates the user before the resources are resolved and provides the repository connection for the duration of the request.
 */
public class AuthenticationFilter implements Filter {
  private static final String AUTH_SESSION_KEY = "AuthenticationFilter_Auth";

  public void process ( FilterChain chain, Request request, Response response ) {

    try {
      initConnection ( request );
    } catch ( LoginException e ) {
      // send unauthorized response status, force user authentication
      response.setStatus ( Response.Status.SC_UNAUTHORIZED );
      ArrayList<String> l = new ArrayList<String> ();
      l.add ( "Basic realm=\"WebDAV\"" );
      // NB: in 1.4.3, "Basic realm=" was added automatically, but not in 1.5
      // l.add ( "WebDAV" );
      response.setAuthenticateHeader ( l );

      // send some content, KDE's Dolphin thinks the resource doesn't exist
      // otherwise
      // TODO: check if this problem persists with Milton's handling of
      // unauthorized responses
      try {
        final byte[] bytes = "Unauthorized\n\n".getBytes ( "UTF-8" );
        response.getOutputStream ().write ( bytes );
        response.setContentLengthHeader ( (long) bytes.length );
        response.getOutputStream ().close ();
      } catch ( IOException e1 ) {
        throw new RuntimeException ( e1 );
      }

      // abort processing
      return;
    }
    // either user is authenticated, or "guest" browsing is allowed
    chain.process ( request, response );
  }

  /**
   * Initialize the connection using the authentication credentials from the current request or from the session cache.
   * 
   * @throws Exception
   * 
   */
  protected void initConnection ( Request request ) throws LoginException {
    // initialize connection, use authorization from HTTP headers or session
    // cache
    Auth auth = getRequestAuthorization ( request );
    if ( auth == null ) {
      throw new LoginException ( "Login required, guest access disabled." );
    }
  }

  protected Auth getRequestAuthorization ( Request request ) {
    Auth auth = request.getAuthorization ();
    if ( auth == null ) {
      // try authentication data stored in session
      if ( request instanceof ServletRequest ) {
        auth = (Auth) ( (ServletRequest) request ).getSession ().getAttribute ( AUTH_SESSION_KEY );
      }
    } else {
      // auth from request, keep in session
      if ( request instanceof ServletRequest ) {
        ( (ServletRequest) request ).getSession ().setAttribute ( AUTH_SESSION_KEY, auth );
      }
    }
    return auth;
  }

}